﻿using System.Collections;
using System.Collections.Generic;

namespace ControllerLayer.AStar
{
    public class Path<TNode> : IEnumerable<TNode>
    {
        #region PublicProperties

        /// <summary>
        /// Gets the last step.
        /// </summary>
        /// <value>The last step.</value>
        public TNode CurrentNode { get; private set; }

        /// <summary>
        /// Gets the previous steps.
        /// </summary>
        /// <value>The previous steps.</value>
        public Path<TNode> PreviousSteps { get; private set; }

        /// <summary>
        /// Gets the total cost.
        /// </summary>
        /// <value>The total cost.</value>
        public double TotalCost { get; private set; }

        #endregion PublicProperties

        #region Constructors

        /// <summary>
        /// Initializes a new instance of the <see cref="ControllerLayer.AStar.Path{Node}"/> class.
        /// </summary>
        /// <param name="currentNode">Last step.</param>
        /// <param name="previousSteps">Previous steps.</param>
        /// <param name="totalCost">Total cost.</param>
        private Path(TNode currentNode, Path<TNode> previousSteps, double totalCost)
        {
            CurrentNode = currentNode;
            PreviousSteps = previousSteps;
            TotalCost = totalCost;
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="ControllerLayer.AStar.Path{Node}"/> class.
        /// </summary>
        /// <param name="start">Start.</param>
        public Path(TNode start)
            : this(start, null, 0)
        {
        }

        #endregion Constructors

        /// <summary>
        /// Adds a step to the path.
        /// </summary>
        /// <returns>The new path.</returns>
        /// <param name="step">The step.</param>
        /// <param name="stepCost">The step cost.</param>
        public Path<TNode> AddStep(TNode step, double stepCost)
        {
            return new Path<TNode>(step, this, TotalCost + stepCost);
        }

        #region EnumerableImplementation

        /// <summary>
        /// Gets the enumerator.
        /// </summary>
        /// <returns>The enumerator.</returns>

        public IEnumerator<TNode> GetEnumerator()
        {
            for (Path<TNode> p = this; p != null; p = p.PreviousSteps)
                yield return p.CurrentNode;
        }

        /// <summary>
        /// Gets the enumerator.
        /// </summary>
        /// <returns>The enumerator.</returns>
        IEnumerator IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }

        #endregion EnumerableImplementation
    }
}